package cn.enjoy.tool.juc;

import lombok.Data;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * Mutex自定义锁    实现Lock接口，并拥有静态类——Sync队列同步器
 *
 * @author K
 * @date 2021/7/31 下午3:13
 */
@Data
public class Mutex implements Lock {

    private final Sync sync = new Sync();
    private int sum = 0;


    public static void main(String[] args) {
        Mutex mutex = new Mutex();

        ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        for (int i = 0; i < 10; i++) {
            executorService.execute(() -> {
                if (mutex.tryLock()) {
                    int sum = mutex.getSum();
                    mutex.setSum(sum + 1);
                }
                mutex.unlock();
            });
        }

        // 等待多线程任务执行完毕
        executorService.shutdown();
        while (true) {
            if (executorService.isTerminated()) {
                break;
            }
        }

        System.out.println(mutex.getSum());
    }

    @Override
    public void lock() {
        sync.acquire(1);
    }

    @Override
    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(time));
    }

    @Override
    public void unlock() {
        sync.release(1);
    }

    @Override
    public Condition newCondition() {
        return sync.newCondition();
    }

    public boolean isLocked() {
        return sync.isHeldExclusively();
    }

    public boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }


    /**
     * state 1占用 0释放
     */
    static class Sync extends AbstractQueuedSynchronizer {

        /**
         * 尝试获取锁
         */
        @Override
        protected boolean tryAcquire(int arg) {
            // CAS 尝试设置1占用，并更新为当前线程占用
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        /**
         * 释放锁
         */
        @Override
        protected boolean tryRelease(int arg) {
            if (getState() == 0) {
                throw new IllegalMonitorStateException();
            }
            // 清除当前线程占用
            setExclusiveOwnerThread(null);
            // 设置状态为0释放
            setState(0);
            return true;
        }

        /**
         * 是否处于占用状态
         */
        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }

        Condition newCondition() {
            return new ConditionObject();
        }
    }

}
